const { Liquid, Tokenizer, Hash, Context } = require("liquidjs");
const { TypeGuards, evalQuotedToken, evalToken } = require("liquidjs");
const { sectionPath, includePath } = require("../../util");

const { __assign } = require("tslib");
const fs = require("fs");

function optimize(templates) {
    if (templates.length === 1 && TypeGuards.isHTMLToken(templates[0].token)) return templates[0].token.getContent();
    return templates;
}

function renderFilePath(file, ctx, liquid) {
    if (typeof file === "string") return file;
    if (Array.isArray(file)) return liquid.renderer.renderTemplates(file, ctx);
    return evalToken(file, ctx);
}
function parseFilePath(tokenizer, liquid) {
    if (liquid.options.dynamicPartials) {
        const file = tokenizer.readValue();
        if (file === undefined) throw new TypeError(`illegal argument "${tokenizer.input}"`);
        if (file.getText() === "none") return null;
        if (TypeGuards.isQuotedToken(file)) {
            const templates = liquid.parse(evalQuotedToken(file));
            return optimize(templates);
        }
        return file;
    }
    const tokens = [...tokenizer.readFileNameTemplate(liquid.options)];
    const templates = optimize(liquid.parser.parseTokens(tokens));
    return templates === "none" ? null : templates;
}

exports.section = {
    parseFilePath,
    renderFilePath,
    parse: function (token, remainTokens) {
        const args = token.args;
        const tokenizer = new Tokenizer(args, this.liquid.options.operatorsTrie);
        tokenizer.input = tokenizer.input.replace(/[\{|\}]/g, "");
        this["file"] = this.parseFilePath(tokenizer, this.liquid);
        this["currentFile"] = token.file;
        this.hash = new Hash(tokenizer.remaining());
    },
    render: function* (ctx, emitter) {
        const { liquid, hash } = this;
        const filepath = yield this.renderFilePath(this["file"], ctx, liquid);
        const childCtx = new Context({}, ctx.opts, { sync: ctx.sync, globals: ctx.globals, strictVariables: ctx.strictVariables });
        let scope = childCtx.bottom();
        const section =  JSON.parse(fs.readFileSync(sectionPath(filepath,'json'),'utf-8'));
        if(section.schema){
            var id = new Date().getTime();
            section.schema.default["block_id"] = id
            scope['section'] = section.schema.default;
        }
        __assign(scope, yield hash.render(ctx));
        const templates = yield liquid._parsePartialFile(sectionPath(filepath,'liquid'), childCtx, this["currentFile"]);
        yield liquid.renderer.renderTemplates(templates, childCtx, emitter);
    }
};

exports.include = {
    parseFilePath,
    renderFilePath,
    parse: function (token, remainTokens) {
        const tokenizer = new Tokenizer(token.args, this.liquid.options.operatorsTrie);
        tokenizer.input = tokenizer.input.replace(/[\{|\}]/g, "");
        this["file"] = this.parseFilePath(tokenizer, this.liquid);
        this["currentFile"] = token.file;
        this.hash = new Hash(tokenizer.remaining());
    },
    render: function* (ctx, emitter) {
        const { liquid, hash } = this;
        const filepath = yield this.renderFilePath(this["file"], ctx, liquid);
        const childCtx = new Context({}, ctx.opts, { sync: ctx.sync, globals: ctx.globals, strictVariables: ctx.strictVariables });
        const scope = childCtx.bottom();
        if(ctx.bottom().section_id){
            scope['section_id'] = ctx.bottom().section_id
        }
        __assign(scope, yield hash.render(ctx));
        const templates = yield liquid._parsePartialFile(includePath(filepath,'liquid'), childCtx, this["currentFile"]);
        yield liquid.renderer.renderTemplates(templates, childCtx, emitter);
    }
};

exports.system_include = {
    parseFilePath,
    renderFilePath,
    parse: function (token, remainTokens) {
        const tokenizer = new Tokenizer(token.args, this.liquid.options.operatorsTrie);
        tokenizer.input = tokenizer.input.replace(/[\{|\}]/g, "");
        this["file"] = this.parseFilePath(tokenizer, this.liquid);
        this["currentFile"] = token.file;
        this.hash = new Hash(tokenizer.remaining());
    },
    render: function* (ctx, emitter) {
        const { liquid, hash } = this;
        const filepath = yield this.renderFilePath(this["file"], ctx, liquid);
        const childCtx = new Context({}, ctx.opts, { sync: ctx.sync, globals: ctx.globals, strictVariables: ctx.strictVariables });
        const scope = childCtx.bottom();
        __assign(scope, yield hash.render(ctx));
        if (!filepath) {
            const templates = yield liquid._parsePartialFile(devPath(`/snippets/${this.file.propertyName}.liquid`), childCtx, this["currentFile"]);
            yield liquid.renderer.renderTemplates(templates, childCtx, emitter); // liquid.renderFile(templates, childCtx);
        } else {
            if (fsExistsSync(devPath(`/snippets/${filepath}.liquid`))) {
                const templates = yield liquid._parsePartialFile(devPath(`/snippets/${filepath}.liquid`), childCtx, this["currentFile"]);
                yield liquid.renderer.renderTemplates(templates, childCtx, emitter);
            } else {
                return "";
            }
        }
    }
};
